package com.audaque.springboot.foshanupload.core.util.encode;

import cn.hutool.crypto.symmetric.AES;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


@Slf4j
@Component
public class AesUtil {

    /**
     * 解密
     * @param userKey
     * @param content
     * @return
     */
    @SneakyThrows
    public static String decrypt(String userKey, String content) {
        byte[] key = calculateCryptoKey(userKey);

        try {
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] result = Base64.decodeBase64(content.getBytes("UTF-8"));
            return new String(cipher.doFinal(result), "UTF-8");
        } catch (Exception e) {
            log.error("oa decrypt error:{}", e);
        }
        return null;
    }

    /**
     * 加密
     * @param userKey
     * @param content
     * @return
     * @throws Exception
     */
    @SneakyThrows
    public static String encrypt(String userKey, String content) {
        byte[] key = calculateCryptoKey(userKey);

        try {
            Cipher aesECB = Cipher.getInstance("AES/ECB/PKCS5Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            aesECB.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            byte[] result = aesECB.doFinal(content.getBytes("UTF-8"));
            return new String(Base64.encodeBase64(result));
        } catch (Exception e) {
            log.error("oa encrypt error:{}", e);
        }
        return null;
    }

    @SneakyThrows
    public static byte[] calculateCryptoKey(String userKey) {
        byte[] shaBytes = sha256(userKey);
        byte[] key = shaBytes;
        key = new byte[8];
        System.arraycopy(shaBytes, 0, key, 0, 8);
        return new String(Hex.encodeHex(key)).getBytes("UTF-8");
    }

    public static byte[] sha256(String str) {
        if (str == null) {
            return null;
        }

        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(str.getBytes("UTF-8"));
            return hash;
        } catch (NoSuchAlgorithmException e) {
            log.error("oa NoSuchAlgorithmException error:{}", e);
        } catch (UnsupportedEncodingException e) {
            log.error("oa UnsupportedEncodingException error:{}", e);
        }

        return null;
    }

    /**
     * 签名
     * @param content
     * @param appid
     * @param appSecurity
     * @return
     */
    public static String calculateSignature(String content, String appid, String appSecurity) {
        StringBuffer key = new StringBuffer(content).append(appid).append(appSecurity);

        String encodeStr = null;
        try {
            MessageDigest md = null;
            md = MessageDigest.getInstance("MD5");
            md.update(key.toString().getBytes("UTF-8"));
            byte[] digest = md.digest();
            encodeStr = byteToHexString(digest);
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        }
        return encodeStr;
    }

    /**
     * 将指定byte数组转换成16进制字符串
     * @param b
     * @return
     */
    public static String byteToHexString(byte[] b) {
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            hexString.append(hex.toUpperCase());
        }
        return hexString.toString();
    }

    @SneakyThrows
    public static String aesEncryptWithIv(String iv, String userKey, String content) {
        byte[] key = calculateCryptoKey(userKey);
        AES aes = new AES("CBC", "PKCS7Padding", key, iv.getBytes("UTF-8"));
        byte[] aesBytes = aes.encrypt(content);
        return cn.hutool.core.codec.Base64.encode(aesBytes);
    }

    @SneakyThrows
    public static String aesDecryptWithIv(String iv, String userKey, String content) {
        byte[] key = calculateCryptoKey(userKey);
        AES aes = new AES("CBC", "PKCS7Padding", key, iv.getBytes("UTF-8"));
        return aes.decryptStr(cn.hutool.core.codec.Base64.decode(content));
    }

}
